﻿using System;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using Spencen.Mobile.UI.Primitives;

namespace Spencen.Mobile.UI
{
    public class DrawingElementCollection : Collection<DrawingElement>
    {
        private readonly DrawingElement _parent;

        internal DrawingElementCollection( DrawingElement parent )
        {
            _parent = parent;
        }

        public event EventHandler CollectionChanged;

        protected override void InsertItem( int index, DrawingElement item )
        {
            base.InsertItem( index, item );

            item.Parent = _parent;
            item.Host = _parent.Host;

            OnCollectionChanged();
        }

        protected override void RemoveItem( int index )
        {
            Items[ index ].Parent = null;
            base.RemoveItem( index );
            OnCollectionChanged();
        }


        private void OnCollectionChanged()
        {
            var handler = CollectionChanged;
            if ( handler != null )
                CollectionChanged( this, EventArgs.Empty );
        }

        public DrawingElement HitTest( Point hitPoint, GraphicsContext context )
        {
            // Loop in reverse to check topmost children first since they will "cover" previous children.
            foreach ( var element in Items.Reverse() )
            {
                if ( element.IsHitTestVisible )
                {
                    var childContext = new GraphicsContext( (Graphics) null, element );
                    var hitPointTransformedToChild = childContext.TransformedPointsReverse( new Point[] { hitPoint } )[ 0 ];

                    var container = element as DrawingContainer;
                    // If the element we've hit is a container that supports exposing its children then keep drilling in
                    // recursively to try and find a child element.
                    if ( container != null && container.HitTestOnChildren )
                    {
                        var childElement = container.Children.HitTest( hitPointTransformedToChild, childContext );
                        if ( childElement != null )
                            return childElement;
                    }

                    if ( element.HitTest( hitPointTransformedToChild, context ) )
                    {
                        // If no child element was hit or exposed then we still return the parent.
                        return element;
                    }
                }
            }
            return null;
        }
    }
}
